package com.ftg.learn.common.util;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author 布衣
 */
public class KeyPairUtil {

    /**
     * 生成RSA密钥对
     *
     * 此方法用于创建一个RSA算法的密钥对，包括公钥和私钥
     * 密钥对的生成是加密过程的基础，特别是在公钥加密体系中
     * RSA是一种非对称加密算法，需要一对密钥来完成加密和解密过程
     *
     * @return KeyPair对象，包含生成的公钥和私钥
     * @throws NoSuchAlgorithmException 如果无法找到指定算法的提供者
     */
    public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
        // 创建RSA算法的密钥对生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器，指定密钥长度为2048位
        // 密钥长度影响安全性，长度越长安全性越高，但相应的处理时间也会增加
        keyPairGenerator.initialize(2048);
        // 生成并返回密钥对
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 将字节数组形式的密钥编码为Base64字符串
     *
     * @param keyBytes 密钥的字节数组表示
     * @return 编码后的Base64字符串
     */
    public static String encodeKey(byte[] keyBytes) {
        // 使用Base64编码器将密钥字节数组编码为字符串
        return Base64.getEncoder().encodeToString(keyBytes);
    }

    /**
     * 将字符串形式的密钥解码为字节数组
     * 该方法主要用于解码使用Base64编码的密钥字符串，以便在加密/解密过程中使用
     *
     * @param keyString Base64编码的密钥字符串
     * @return 解码后的字节数组形式的密钥
     */
    public static byte[] decodeKey(String keyString) {
        // 使用Base64解码器对密钥字符串进行解码
        return Base64.getDecoder().decode(keyString);
    }

    /**
     * 从字符串形式的私钥中获取PrivateKey对象
     * 该方法主要用于解析PEM格式的私钥字符串，将其转换为PrivateKey对象，以便在Java程序中使用
     *
     * @param privateKeyPEM 包含PEM格式私钥的字符串
     * @return 解析后的PrivateKey对象
     * @throws Exception 如果私钥解析过程中发生错误，则抛出异常
     */
    public static PrivateKey getPrivateKey(String privateKeyPEM) {
        // 解码私钥字符串，将其转换为字节数组
        byte[] encoded = decodeKey(privateKeyPEM);

        // 创建PKCS8EncodedKeySpec对象，用于存储解码后的私钥信息
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);

        // 通过KeyFactory生成PrivateKey对象，指定算法为RSA
        try {
            return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从给定的公钥字符串中获取PublicKey对象
     * 该方法主要用于解析以字符串形式提供的公钥，并将其转换为PublicKey对象，以便在Java程序中使用
     *
     * @param publicKeyPEM 公钥的字符串表示，通常以"-----BEGIN PUBLIC KEY-----"开始，以"-----END PUBLIC KEY-----"结束
     * @return PublicKey对象，可以用于加密和验证等操作
     * @throws Exception 如果公钥解析过程中发生错误，则抛出此异常
     */
    public static PublicKey getPublicKey(String publicKeyPEM){
        // 解码公钥字符串，将其转换为字节数组
        byte[] encoded = decodeKey(publicKeyPEM);

        // 创建X509EncodedKeySpec对象，用于将编码的公钥转换为Java可识别的格式
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);

        // 使用KeyFactory生成PublicKey对象，此处指定算法为RSA
        try {
            return KeyFactory.getInstance("RSA").generatePublic(keySpec);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

}